package core

import (
	"fmt"
	"net/http"

	"github.com/goccy/go-json"
	"github.com/tidwall/gjson"

	"codeberg.org/vnpower/pixivfe/v2/audit"
	"codeberg.org/vnpower/pixivfe/v2/i18n"
	"codeberg.org/vnpower/pixivfe/v2/server/session"
)

func GetDiscoveryArtwork(auditor *audit.Auditor, r *http.Request, mode string) ([]ArtworkBrief, error) {
	token := session.GetUserToken(r)

	URL := GetDiscoveryURL(mode, 100)

	var artworks []ArtworkBrief

	resp, err := API_GET_UnwrapJson(r.Context(), auditor, URL, token, r.Header)
	if err != nil {
		return nil, err
	}

	resp, err = session.ProxyImageUrl(r, resp)
	if err != nil {
		return nil, err
	}

	if !gjson.Valid(resp) {
		return nil, i18n.Errorf("Invalid JSON: %v", resp)
	}
	data := gjson.Get(resp, "thumbnails.illust").String()

	err = json.Unmarshal([]byte(data), &artworks)
	if err != nil {
		return nil, err
	}

	// Populate thumbnails for each artwork
	for id, artwork := range artworks {
		if err := artwork.PopulateThumbnails(auditor); err != nil {
			auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
			return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
		}
		artworks[id] = artwork
	}

	return artworks, nil
}

func GetDiscoveryNovels(auditor *audit.Auditor, r *http.Request, mode string) ([]NovelBrief, error) {
	token := session.GetUserToken(r)

	URL := GetDiscoveryNovelURL(mode, 100)

	var novels []NovelBrief

	resp, err := API_GET_UnwrapJson(r.Context(), auditor, URL, token, r.Header)
	if err != nil {
		return nil, err
	}

	resp, err = session.ProxyImageUrl(r, resp)
	if err != nil {
		return nil, err
	}

	if !gjson.Valid(resp) {
		return nil, i18n.Errorf("Invalid JSON: %v", resp)
	}
	data := gjson.Get(resp, "thumbnails.novel").String()

	err = json.Unmarshal([]byte(data), &novels)
	if err != nil {
		return nil, err
	}

	return novels, nil
}

// GetDiscoveryUsers retrieves users on the discovery page along with their associated artworks and novels.
func GetDiscoveryUsers(auditor *audit.Auditor, r *http.Request) ([]User, error) {
	token := session.GetUserToken(r)

	URL := GetDiscoveryUserURL(100)

	var users []User

	resp, err := API_GET_UnwrapJson(r.Context(), auditor, URL, token, r.Header)
	if err != nil {
		return nil, err
	}

	resp, err = session.ProxyImageUrl(r, resp)
	if err != nil {
		return nil, err
	}

	// Validate JSON response
	if !gjson.Valid(resp) {
		return nil, i18n.Errorf("Invalid JSON: %v", resp)
	}

	// Extract and unmarshal users
	userData := gjson.Get(resp, "users").Raw
	if err = json.Unmarshal([]byte(userData), &users); err != nil {
		return nil, fmt.Errorf("error unmarshalling users in GetDiscoveryUser: %w", err)
	}

	// Extract and unmarshal artworks
	artworkData := gjson.Get(resp, "thumbnails.illust").Raw
	var artworks []ArtworkBrief
	if err = json.Unmarshal([]byte(artworkData), &artworks); err != nil {
		return nil, fmt.Errorf("error unmarshalling artworks in GetDiscoveryUser: %w", err)
	}

	// Populate thumbnails for each artwork
	for id, artwork := range artworks {
		if err := artwork.PopulateThumbnails(auditor); err != nil {
			auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
			return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
		}
		artworks[id] = artwork
	}

	// Extract and unmarshal novels
	novelData := gjson.Get(resp, "thumbnails.novel").Raw
	var novels []NovelBrief
	if err = json.Unmarshal([]byte(novelData), &novels); err != nil {
		return nil, fmt.Errorf("error unmarshalling novels in GetDiscoveryUser: %w", err)
	}

	// Associate artworks and novels with users
	associateContentWithUsers(&users, artworks, novels, auditor)

	return users, nil
}

// associateContentWithUsers associates artworks and novels with their respective users.
func associateContentWithUsers(users *[]User, artworks []ArtworkBrief, novels []NovelBrief, auditor *audit.Auditor) {
	userMap := make(map[string]*User, len(*users))
	for i := range *users {
		user := &(*users)[i]
		userMap[user.ID] = user
	}

	// Associate artworks with users
	for _, artwork := range artworks {
		if user, exists := userMap[artwork.ArtistID]; exists {
			user.Artworks = append(user.Artworks, artwork)
		}
	}

	// Associate novels with users
	for _, novel := range novels {
		if user, exists := userMap[novel.UserID]; exists {
			user.Novels = append(user.Novels, novel)
		}
	}
}
